<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>18_Canvas-动画关键帧(requestAnimationFrame)</title>
  <!-- 
  `requestAnimationFrame`  是一个用于创建平滑动画的浏览器 API，它可以让你在浏览器的下一次重绘之前执行一个函数。
  1. 基本概念
  -  `requestAnimationFrame`  是一种高效的动画实现方式，它告诉浏览器你希望执行一个动画，并请求在下一个重绘之前调用指定的函数。
  - 该方法相较于使用  `setTimeout`  或  `setInterval`  更为高效，因为它能够根据浏览器的刷新率进行优化，从而提供更加平滑的动画效果。

  2. 使用方式
   语法：
  requestAnimationFrame(callback);
  - callback：一个函数，表示在下一个重绘时需要执行的代码。

   示例：
  let start = null;

  function step(timestamp) {
    if (!start) start = timestamp;
    const progress = timestamp - start;

    // 在这里进行动画的更新
    // 例如，更新元素的位置、透明度等
    console.log(progress); // 记录经过的时间

    // 如果动画未完成，继续请求下一帧
    if (progress < 2000) { // 假设动画持续 2000 毫秒
      requestAnimationFrame(step);
    }
  }

  // 开始动画
  requestAnimationFrame(step);
  3. 优点
  - 性能优化： `requestAnimationFrame`  会在浏览器的下一个重绘之前执行回调函数，浏览器可以更好地优化性能，减少 CPU 和 GPU 的负担。
  - 平滑动画：由于  `requestAnimationFrame`  与浏览器的刷新率相匹配，动画效果通常更加平滑，避免了因使用定时器导致的卡顿现象。
  - 暂停和恢复：当用户切换标签页或最小化浏览器时， `requestAnimationFrame`  会自动暂停，避免了不必要的计算和资源浪费。

  4. 注意事项
  - 回调函数的参数： `requestAnimationFrame`  的回调函数会接收到一个  `timestamp`  参数，表示当前的时间戳，可以用来计算动画进度。
  - 取消动画：可以使用  `cancelAnimationFrame`  来取消之前通过  `requestAnimationFrame`  注册的动画。

   示例：
  const animationId = requestAnimationFrame(step);
  // 取消动画
  cancelAnimationFrame(animationId);

  5. 总结
  `requestAnimationFrame`  是实现高效和流畅动画的关键工具。它允许开发者在浏览器的重绘周期内执行动画代码，从而提供更好的性能和用户体验。通过合理使用  `requestAnimationFrame` ，可以创建出更平滑的动画效果，提升 Web 应用的交互性和视觉吸引力。
  -->
  <style>
    body {
      margin: 0;
      padding: 0;
      background-image: url(../../images/grid.png);
    }

    canvas {
      background-color: rgba(255, 0, 0, 0.1);
    }
  </style>
</head>

<body>

  <canvas id="tutorial" width="300" height="300px">
    你的浏览器不兼容Canvas,请升级您的浏览器!
  </canvas>
  <script>
    // 在浏览器下一次重绘之前会回调该函数的回调函数draw
    // requestAnimationFrame(draw)
    // let startTime = new Date().getTime()
    // /*
    //   一秒钟会被回调  61s 次
    // */
    // function draw() {
    //   let endTime = new Date().getTime()
    //   if (endTime - startTime > 1000) {
    //     return
    //   }
    //   console.log('draw')
    //   requestAnimationFrame(draw)
    // }

    window.onload = function () {
      // 1. 获取canvas元素
      var canvas = document.getElementById('tutorial');
      // 2. 获取绘图上下文
      var ctx = canvas.getContext('2d');

      requestAnimationFrame(draw)

      function draw() {
        let second = new Date().getSeconds()
        
        ctx.clearRect(0, 0, 300, 300)
        ctx.save()

        ctx.translate(100, 100)
        ctx.rotate(Math.PI * 2 / 60 * second)
        ctx.lineWidth = 6
        ctx.lineCap = 'round' // 线条末端样式
        ctx.strokeStyle = '#000'

        ctx.beginPath()
        ctx.moveTo(0, 0)
        ctx.lineTo(0, -80)
        ctx.stroke()
        ctx.restore()

        requestAnimationFrame(draw)
      }

    }
  </script>

</body>

</html>